package com.qimu.saiyou.consumer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.qimu.saiyou.common.ErrorCode;
import com.qimu.saiyou.config.DelayExchangeConfig;
import com.qimu.saiyou.exception.BusinessException;
import com.qimu.saiyou.model.entity.*;
import com.qimu.saiyou.service.*;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: FeiXiang
 * @Date: 2023/07/21 06:13:02
 * @Version: 1.0    队列的消费者 结算
 * @Description:
 */
@Component
@Slf4j
public class DeadlineQueueConsumer {
    @Resource
    private CompetitionService competitionService;
    @Resource
    private JoinCompeteService joinCompeteService;
    @Resource
    private CompeteService competeService;
    @Resource
    private TeamService teamService;
    @Resource
    private CompeteUserService competeUserService;
    @Resource
    private UserService userService;
    @Resource
    private CompeteExamService competeExamService;

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    @RabbitListener(queues = DelayExchangeConfig.DEADLINE_DELAY_QUEUE, ackMode = "MANUAL")
    public void deadline(Message message, Channel channel) {
        try {
            String body = new String(message.getBody());
            log.info("接收到截止报名消息：" + body);
            Competition competition = JSONUtil.toBean(JSONUtil.toJsonStr(body), Competition.class);
            competition = competitionService.getById(competition.getId());
            if (ObjectUtils.anyNotNull(competition, competition.getId()) && competition.getId() > 0) {
                try {
                    if ("end".equals(competition.getCompetitionStatus())) {
                        throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "竞赛已结束");
                    }
                    if ("cancel".equals(competition.getCompetitionStatus())) {
                        throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "竞赛已取消");
                    }
                    if ("running".equals(competition.getCompetitionStatus())) {
                        throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "竞赛已开始");
                    }
                    // 获取所有加入的队伍
                    LambdaUpdateWrapper<JoinCompete> joinCompeteLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                    joinCompeteLambdaUpdateWrapper.eq(JoinCompete::getCompetitionId, competition.getId());
                    List<Long> joinTeamIdList = joinCompeteService.list(joinCompeteLambdaUpdateWrapper).stream().map(JoinCompete::getTeamId).collect(Collectors.toList());
                    if (CollUtil.isEmpty(joinTeamIdList)) {
                        competition.setCompetitionStatus("cancel");
                        competitionService.updateById(competition);
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                        log.info("人数不足已取消比赛");
                        return;
                    }
                    // 打乱List中的元素顺序
                    Collections.shuffle(joinTeamIdList);
                    if (joinTeamIdList.size() % 2 != 0) {
                        Long aLong = joinTeamIdList.get(joinTeamIdList.size() - 1);
                        System.out.println("队伍" + aLong + " 轮空");
                        Compete compete = new Compete();
                        compete.setCompetitionId(competition.getId());
                        compete.setBlueTeamId(aLong);
                        competeService.save(compete);
                        Team team = new Team();
                        team.setId(aLong);
                        team.setCompeteId(compete.getId());
                        assignUsers(compete, team);
                        joinTeamIdList.remove(aLong);
                    }

                    for (int i = 0; i < joinTeamIdList.size(); i += 2) {
                        if (i + 1 < joinTeamIdList.size()) {
                            Compete compete = new Compete();
                            compete.setCompetitionId(competition.getId());
                            Long blueId = joinTeamIdList.get(i);
                            compete.setBlueTeamId(blueId);
                            Long redId = joinTeamIdList.get(i + 1);
                            compete.setRedTeamId(redId);
                            competeService.save(compete);
                            Team blueIdTeam = new Team();
                            blueIdTeam.setId(blueId);
                            blueIdTeam.setCompeteId(compete.getId());
                            assignUsers(compete, blueIdTeam);
                            Team redIdTeam = new Team();
                            redIdTeam.setId(redId);
                            redIdTeam.setCompeteId(compete.getId());
                            assignUsers(compete, redIdTeam);
                        }
                    }
                    competition.setCompetitionStatus("running");
                    competitionService.updateById(competition);
                    Long examId = competition.getExamId();
                    Integer competitionType = competition.getCompetitionType();
                    if (competitionType == 0 && ObjectUtils.isEmpty(examId)) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "线上竞赛请先选择竞赛考试");
                    }
                    CompeteExam competeExam = competeExamService.getById(examId);
                    if (competeExam == null) {
                        throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "考试不存在");
                    }
                    competeExam.setState("open");
                    competeExamService.updateById(competeExam);
                } catch (Exception e) {
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                }
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error(e.getMessage());
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    private void assignUsers(Compete compete, Team team) throws IOException {
        teamService.updateById(team);
        team = teamService.getById(team.getId());
        if (team != null) {
            String teamUsersId = team.getUsersId();
            List<Long> teamIdList = JSONUtil.toList(teamUsersId, Long.class);
            teamIdList.forEach(userId -> {
                CompeteUser competeUser = new CompeteUser();
                competeUser.setUserId(userId);
                competeUser.setCompeteId(compete.getId());
                competeUserService.save(competeUser);
            });
        }
    }
}
